home *** CD-ROM | disk | FTP | other *** search
- #!/usr/local/bin/perl
- #
- # Copyright (c) 1993, 1994 by Silicon Systems Inc.
- #
- # Permission to use, copy, modify, and distribute this software for any
- # purpose with or without fee is hereby granted, provided that this
- # copyright notice appear in all copies, and that the name of Silicon
- # Systems Inc. not be used in advertising or publicity pertaining to
- # distribution of the document or software without specific,
- # written prior permission.
- #
- # THE SOFTWARE IS PROVIDED "AS IS" AND SILICON SYSTEMS INC. DISCLAIMS ALL
- # WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
- # OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL SILICON SYTEMS
- # INC. BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- # DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- # PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- # SOFTWARE.
- #
- # Author: Don Lewis <gdonl@gv.ssi1.com>
- #
- # This perl script reads the /etc/named.boot file to find all the zone
- # files. It reads the zone files and produces a report listing the
- # hosts sorted by both name and address in a format similar to that of
- # /etc/hosts (the difference being that this report contains multiple
- # address fields for multi-homed hosts). This script checks that the
- # A RRs and PTR RRs match up, and also knows about CNAME RRs.
- #
- # This script is fairly dependent on having a complete set of the zone
- # files for a domain (both forward and reverse) accessable.
- #
- # $Id: dnsrpt,v 8.2 1996/10/25 17:07:56 vixie Exp $
- #
-
- sub getnonblank {
- local ($line, $instring, $inparens, $saweof);
- local ($handle) = @_;
-
- $instring = 0;
- $inparens = 0;
- $saweof = 0;
-
- do {
- $line = '';
- do {
- $c = getc($handle);
- if ($c eq ';') {
- do {
- $c = getc($handle);
- if ($c eq '') {
- last;
- }
- } while ($c ne "\n");
- }
- if ($c eq '') {
- $saweof = 1;
- last;
- } elsif ($c eq ';') {
- $line .= $c;
- } else {
- $line .= $c;
- }
- if ($instring) {
- if ($c eq '"') {
- $instring = 0;
- }
- } else {
- if ($c eq '"') {
- $instring = 1;
- } elsif ($c eq '(') {
- $inparens = 1;
- } elsif ($c eq ')') {
- $inparens = 0;
- }
- }
- } while ( $inparens || $c ne "\n" );
- } while ((! $saweof) && (split(/[ \t\n]/, $line) == 0));
- return($line);
- }
-
- sub parsezone {
- local ($origin) = $_[0];
- local ($zonefile) = $_[1];
- local ($zonedata);
- local ($owner, $lcowner);
- local ($hostname, $lchostname);
-
- if ($origin ne '.') {
- $origin .= '.';
- }
-
- if ($directory ne '') {
- $zonefile = $directory . '/' . $zonefile;
- }
-
- if (! -f $zonefile) {
- die "zone file '" . $zonefile . "' for zone '" . $origin .
- "' is not a file\n";
- }
- if (open(zone, $zonefile) != 1) {
- die "can't open zone file '" . $zonefile . "' for zone '" . $origin .
- "'\n";
- }
-
- while ($zonedata = &getnonblank(zone)) {
- split(/[ \t\n]+/, $zonedata);
- if ($_[0] eq '$ORIGIN') {
- $origin = $_[1];
- } else {
- if ($_[0] ne '') {
- if ($_[0] eq '@') {
- $owner = $origin;
- } elsif ($_[0] =~ /.*\.$/) {
- $owner = $_[0];
- } elsif ($origin eq '.') {
- $owner = $_[0] . '.';
- } else {
- $owner = $_[0] . '.' . $origin;
- }
- }
- ($lcowner = $owner) =~ y/A-Z/a-z/;
- shift; # skip owner
- if ($_[0] =~ /^[0-9]+$/) {
- shift; # skip ttl
- }
- if ($_[0] ne 'IN') {
- print "skipping non-IN class RR ", $zonedata;
- next;
- }
- shift; # skip class
- if ($_[0] eq 'A') {
- if ($addrtohost{$_[1]}) {
- local (@tmpvar);
- foreach $var (split(/ /, $addrtohost{$_[1]})) {
- $tmpvar{$var} = 'junk';
- }
- if (! $tmpvar{$lcowner} ) {
- $addrtohost{$_[1]} .= " " . $owner;
- }
- } else {
- $addrtohost{$_[1]} = $owner;
- }
- if ($hosttoaddr{$lcowner}) {
- local (@tmpvar);
- foreach $var (split(/ /, $hosttoaddr{$lcowner})) {
- $tmpvar{$var} = 'junk';
- }
- if (! $tmpvar{$_[1]} ) {
- $hosttoaddr{$lcowner} .= " " . $_[1];
- }
- } else {
- $hosttoaddr{$lcowner} = $_[1];
- }
- } elsif ($_[0] eq 'CNAME') {
-
- if ($_[1] =~ /.*\.$/) {
- $hostname = $_[1];
- } elsif ($origin eq '.') {
- $hostname = $_[1] . '.';
- } else {
- $hostname = $_[1] . '.' . $origin;
- }
- ($lchostname = $hostname) =~ y/A-Z/a-z/;
-
- if ($hosttocname{$lchostname}) {
- $hosttocname{$lchostname} .= " " . $owner;
- } else {
- $hosttocname{$lchostname} = $owner;
- }
- } elsif ($_[0] eq 'PTR') {
- if ($ptrtohost{$lcowner}) {
- $ptrtohost{$lcowner} .= " " . $_[1];
- } else {
- $ptrtohost{$lcowner} = $_[1];
- }
- }
- }
- }
-
- close(zone);
- }
-
- sub cmpaddr {
- local (@addr1) = split(/\./, $a);
- local (@addr2) = split(/\./, $b);
-
- for ($i = 0; $i < 4; $i++) {
- if ($addr1[$i] != $addr2[$i]) {
- return($addr1[$i] - $addr2[$i]);
- }
- }
- return(0);
- }
-
- if (open(bootfile, "</etc/named.boot") != 1) {
- die "can't open /etc/named.boot\n";
- }
-
- while ($cmd = &getnonblank(bootfile)) {
- split(/[ \t\n]+/, $cmd);
- if ($_[0] eq 'directory') {
- $directory = $_[1];
- } elsif ($_[0] eq 'primary') {
- &parsezone( $_[1], $_[2]);
- } elsif ($_[0] eq 'secondary') {
- &parsezone( $_[1], $_[$#_]);
- }
- }
-
- foreach $addr (keys(%addrtohost)) {
- $ptr = $ptrtohost{ join('.', reverse(split(/\./, $addr))) .
- '.in-addr.arpa.' };
- ($lcptr = $ptr) =~ y/A-Z/a-z/;
- $hostname = $addrtohost{$addr};
- @hostname = split(/ /, $hostname);
- ($lchostname = $hostname) =~ y/A-Z/a-z/;
- @lchostname = split(/ /, $lchostname);
- @unmatched = ();
-
- if (! $ptr ) {
- print "address ", $addr,
- " (", $hostname, ") has no matching PTR record\n";
- } else {
- foreach (@lchostname) {
- if ( $lcptr ne $_ ) {
- push( @unmatched, shift( @hostname ) );
- }
- }
- if ( $#lchostname == $#unmatched ) {
- print "address ", $addr, " has name ", $hostname, " and PTR ",
- $ptr, "\n";
- } elsif ( $#unmatched > 1 ) {
- print "address ", $addr, " has extra names ",
- join(' ', @unmatched), "\n";
- } elsif ( $#unmatched > 0 ) {
- print "address ", $addr, " has extra name ", $unmatched[0], "\n";
- }
- }
- }
-
- foreach $ptr (keys(%ptrtohost)) {
- $hostname = $ptrtohost{$ptr};
- ($lchostname = $hostname) =~ y/A-Z/a-z/;
- @parts = split(/\./, $ptr);
-
- if ($parts[$#parts] =~ /^arpa$/i && $parts[$#parts - 1] =~ /^in-addr$/i) {
-
- if ( ! $hosttoaddr{$lchostname} ) {
- if ( $ptrtohost{$lchostname} ) {
- if ( $ptrtohost{$lchostname} ne $ptr ) {
- print "mismatched PTRs for ", $ptr, " and ", $hostname,
- "\n";
- }
- } else {
- print "PTR ", $ptr, " refers to unknown host ", $hostname, "\n";
- }
- } else {
- $addr = $parts[3] . '.' . $parts[2] . '.' . $parts[1] .
- '.' . $parts[0];
-
- if ( ! $addrtohost{$addr} ) {
- print "PTR ", $ptr, " to ", $hostname,
- " has an invalid address\n";
- } elsif ( $hostname ne $addrtohost{$addr} ) {
- # duplicate warning
- # print "PTR ", $ptr, " to ", $hostname, " has address of host ",
- # $addrtohost{$addr}, "\n";
- }
- }
- } elsif ( ! $ptrtohost{$lchostname} ) {
- print "network PTR ", $ptr, " to ", $hostname, " is dangling\n";
- }
- }
-
- print " Hosts Sorted by Name\n\n\n";
-
- foreach $host (sort(keys(%hosttoaddr))) {
- $count = 0;
- foreach $addr (split(/ /, $hosttoaddr{$host})) {
- $count++;
- printf("%-16s", $addr);
- }
- for (; $count < 2; $count++) {
- printf("%-16s", "");
- }
- printf " %s", $host;
- if ($hosttocname{$host}) {
- print ' ', $hosttocname{$host};
- }
- print "\n";
- }
-
- print "\f Hosts Sorted by Address\n\n\n";
-
- foreach $addr (sort(cmpaddr keys(%addrtohost))) {
- printf "%-32s %s", $addr, $addrtohost{$addr};
- if ($hosttocname{$addrtohost{$addr}}) {
- print ' ', $hosttocname{$addrtohost{$addr}};
- }
- print "\n";
- }
-